﻿using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using StudyCompanion.Commons.Encrypt;
using StudyCompanion.Commons.Result;
using StudyCompanion.Core.Enum;
using StudyCompanion.Core.Repository;
using StudyCompanion.Core.Services;
using StudyCompanion.Core.Web;
using StudyCompanion.Dto.User;
using StudyCompanion.Entity.Order;
using StudyCompanion.Entity.Study;
using StudyCompanion.Entity.User;
using StudyCompanion.IServices;
using StudyCompanion.Model.User;

namespace StudyCompanion.Services;

public class UserService : BaseService<Users>, IUserService
{
    private readonly BaseRepository<StuClassEntity> _classRepository;

    public UserService(BaseRepository<Users> repository, BaseRepository<StuClassEntity> classRepository) :
        base(repository)
    {
        _classRepository = classRepository;
    }

    /// <summary>
    ///     获取用户(根据电话号码）
    /// </summary>
    /// <param name="phone"></param>
    /// <returns></returns>
    public async Task<Tuple<bool, Users>> GetUserbyPhone(string phone)
    {
        var userInfo = await _repository.GetFirstAsync(x => x.Phone == phone);
        return userInfo == null ? new Tuple<bool, Users>(false, null) : new Tuple<bool, Users>(true, userInfo);
    }

    /// <summary>
    ///     获取用户(根据用户ID）
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task<Tuple<bool, Users>> GetUserbyId(long userId)
    {
        var userInfo = await _repository.GetFirstAsync(x => x.Id == userId);
        return userInfo == null ? new Tuple<bool, Users>(false, null) : new Tuple<bool, Users>(true, userInfo);
    }

    /// <summary>
    ///     更新用户
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    public bool UpdateUsers(Users dto)
    {
        return _repository.Update(dto);
    }

    /// <summary>
    ///     密码登录
    /// </summary>
    /// <param name="phone">电话号码</param>
    /// <param name="password"></param>
    /// <returns></returns>
    public async Task<Tuple<Users, string>> PasswordLogin(string phone, string password)
    {
        var user = await GetUserbyPhone(phone);
        if (!user.Item1)
            return new Tuple<Users, string>(null, "用户不存在");
        // var loginPassword = MD5Encryption.Encrypt(password, true);
        return !BCrypt.Net.BCrypt.Verify(password, user.Item2.Password)
            ? new Tuple<Users, string>(null, "密码错误")
            : new Tuple<Users, string>(user.Item2, "");
    }

    /// <summary>
    ///     修改用户登录密码
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    public async Task<CommonResult> ChangeUserPassword(long userId, ChangeUserPasswordDto dto)
    {
        var useInfo = await GetUserbyId(userId);
        if (!useInfo.Item1) return Problem("用户不存在");
        var smsCode = RedisHelper.Get($"idSMS:{useInfo.Item2.Phone}");
        if (smsCode != dto.SMSCode) return Problem("验证码错误");
        RedisHelper.Del($"idSMS:{useInfo.Item2.Phone}");
        useInfo.Item2.Password = BCrypt.Net.BCrypt.HashPassword(dto.Password);
        return UpdateUsers(useInfo.Item2) ? Success() : Problem("更新失败");
    }

    /// <summary>
    ///     获取或者添加用户
    /// </summary>
    /// <param name="phone"></param>
    /// <returns></returns>
    public async Task<Users> GetOrInsertUserByPhone(string phone)
    {
        var user = await GetUserbyPhone(phone);
        if (user.Item1) return user.Item2;
        var userInfo = new Users { Phone = phone, ValidTime = DateTime.MinValue, SuperiorUser = 10000 };
        userInfo.Id = await _repository.InsertReturnBigIdentityAsync(userInfo);

        return userInfo;
    }

    /// <summary>
    ///     学生年级
    /// </summary>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public List<StudyClassVo> StudyClass()
    {
        return _classRepository.Where(x => x.IsValid == true && x.IsClass == true)
            .OrderBy(x => x.Sort)
            .Select(x => new StudyClassVo
            {
                Id = x.Id,
                Name = x.Name
            }).ToList();
    }

    /// <summary>
    ///     忘记密码
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    [HttpPost("ForgetPassword")]
    public async Task<CommonResult> ForgetPassword(ForgetPasswordDto dto)
    {
        var useInfo = await GetUserbyPhone(dto.Tel);
        if (!useInfo.Item1) return Problem("用户不存在");
        var smsCode = RedisHelper.Get($"telSMS:{useInfo.Item2.Phone}");
        if (smsCode != dto.SMSCode) return Problem("验证码错误");
        RedisHelper.Del($"telSMS:{useInfo.Item2.Phone}");
        useInfo.Item2.Password = BCrypt.Net.BCrypt.HashPassword(dto.Password);
        return UpdateUsers(useInfo.Item2) ? Success() : Problem("更新失败");
    }

    /// <summary>
    ///     设置支付密码
    /// </summary>
    /// <param name="uId"></param>
    /// <param name="dto"></param>
    /// <exception cref="NotImplementedException"></exception>
    public async Task<CommonResult> ReplenishPayPass(long uId, ReplenishPayPassDto dto)
    {
        var useInfo = await GetUserbyId(uId);
        if (!useInfo.Item1) return Problem("用户不存在");
        var smsCode = RedisHelper.Get($"idSMS:{useInfo.Item2.Phone}");
        if (smsCode != dto.SmsCode) return Problem("验证码错误");
        RedisHelper.Del($"idSMS:{useInfo.Item2.Phone}");
        useInfo.Item2.PayPass = MD5Encryption.Encrypt(dto.PayPass);
        return UpdateUsers(useInfo.Item2) ? Success() : Problem("设置失败");
    }

    /// <summary>
    ///    快速登录手机号获取
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public Tuple<bool, string> SimpleLogin(SimpleLoginDto dto)
    {
        const string url = "https://fc-mp-67c35a5e-6c9b-4d43-a6d4-5fcc2f64f9c0.next.bspapp.com/phone";
        var token = dto.ToJson();
        var isSuccessJson = HttpMethods.HttpPostJson(url, token);
        var isSuccessVo = Json.ToObject<IsSuccessVo>(isSuccessJson);
        return isSuccessVo.success
            ? new Tuple<bool, string>(true, isSuccessVo.phoneNumber)
            : new Tuple<bool, string>(false, isSuccessVo.error.message);
    }

    /// <summary>
    ///     伙伴数据
    /// </summary>
    /// <param name="userContextId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public PartnerVo Partner(long userContextId)
    {
        var partnerVo = new PartnerVo
        {
            ShareNumber = _repository.Where(x => x.SuperiorUser == userContextId).Count(),
            PurchaseNumber = _repository.Queryable<Users, Order>((t1, t2) => new object[]
                {
                    JoinType.Left, t1.Id == t2.UserId
                })
                .Where((t1, t2) => t1.SuperiorUser == userContextId && t2.Status == (int)OrderStatusEnum.Paid &&
                                   t2.TradeState == (int)TradeStateEnum.SUCCESS)
                .GroupBy((t1, t2) => t2.UserId)
                .Count()
        };
        return partnerVo;
    }
}